#!/usr/bin/env python3
# coding=utf-8

"""
证书工具类
"""
import datetime
import json
import os
import stat
import ssl
from ssl import create_default_context, Purpose
from typing import Dict, Optional, Union, Any
from datetime import timezone

from OpenSSL import crypto
CryptoX509 = crypto.X509

from motor.utils.logger import get_logger

logger = get_logger(__name__)

CA_CERTS = "ca_cert"
TLS_CERT = "tls_cert"
TLS_KEY = "tls_key"
TLS_CRL = "tls_crl"
SSL_MUST_KEYS = [CA_CERTS, TLS_CERT, TLS_KEY]

MIN_RSA_LENGTH = 3072
RSA_SHA_256 = "sha256WithRSAEncryption"
RSA_SHA_512 = "sha512WithRSAEncryption"


def validate_certs_and_keys_modulus(server_crt: CryptoX509, server_key: CryptoX509) -> bool:
    """Validate certificate and private key modulus match"""
    try:
        cert_pub_key = server_crt.get_pubkey()
        cert_rsa_key = cert_pub_key.to_cryptography_key()
        cert_modulus = cert_rsa_key.public_numbers().n

        key_rsa_key = server_key.to_cryptography_key()
        key_modulus = key_rsa_key.public_key().public_numbers().n
        return cert_modulus == key_modulus
    except Exception as e:
        logger.error(f"Modulus validation failed: {e}")
        return False


def has_expired(cert: CryptoX509) -> bool:
    """Check if certificate has expired"""
    try:
        before_time_str = cert.get_notBefore().decode("utf-8")
        before_time = datetime.datetime.strptime(before_time_str, "%Y%m%d%H%M%SZ").replace(tzinfo=timezone.utc)
        after_time_str = cert.get_notAfter().decode("utf-8")
        after_time = datetime.datetime.strptime(after_time_str, "%Y%m%d%H%M%SZ").replace(tzinfo=timezone.utc)
        current_time = datetime.datetime.now(timezone.utc)
        return before_time > current_time or current_time > after_time
    except Exception as e:
        logger.error(f"Expiry check failed: {e}")
        return True


def validate_server_certs(server_cert: CryptoX509) -> bool:
    """Validate server certificate integrity and security"""
    try:
        # 1. Check if certificate version is X509v3
        if server_cert.get_version() != 2:
            logger.error("The cert does not use X509v3")
            return False

        decode_format = 'utf-8'
        
        # 2. Check signature algorithm
        pkey_algorithm = server_cert.get_signature_algorithm()
        pkey_algorithm = pkey_algorithm.decode(decode_format)
        if pkey_algorithm not in [RSA_SHA_256, RSA_SHA_512]:
            logger.warning("Insecure encryption algorithm detected")
            # In production environment, this should return False, but temporarily allowed for compatibility

        # 3. Check RSA key length
        pkey = server_cert.get_pubkey()
        key_algorithm_id = pkey.type()
        if key_algorithm_id == crypto.TYPE_RSA:
            rsa_key = pkey.to_cryptography_key()
            rsa_length = rsa_key.key_size
            if rsa_length < MIN_RSA_LENGTH:
                logger.error(f"Insecure RSA key length, required no less than: {MIN_RSA_LENGTH}")
                return False
        else:
            logger.error("Certificate public key must use RSA")
            return False

        # 4. Check certificate purpose
        check_key_cert_sign = False
        check_crl_sign = False
        check_ca_true = False
        num_extensions = server_cert.get_extension_count()
        for index in range(num_extensions):
            ext = server_cert.get_extension(index)
            ext_name = ext.get_short_name()
            if ext_name.decode(decode_format) == "basicConstraints":
                ext_content = str(ext)
                if "CA:TRUE" in ext_content.upper():
                    check_ca_true = True
            if ext_name.decode(decode_format) == "keyUsage":
                ext_content = str(ext)
                if "Certificate Sign" in ext_content:
                    check_key_cert_sign = True
                if "CRL Sign" in ext_content:
                    check_crl_sign = True
        
        if check_key_cert_sign or check_crl_sign or check_ca_true:
            logger.warning(f"The cert is not End Entity cert with check_certificate_sign: {check_key_cert_sign}, "
                         f"check_crl_sign: {check_crl_sign}, check_ca_true: {check_ca_true}")

        # 5. Check if certificate has expired
        if has_expired(server_cert):
            logger.error("Server cert expired")
            return False

        return True
    except Exception as e:
        logger.error(f"Server certificate validation failed: {e}")
        return False


def _check_directory_permissions(cur_path: str) -> None:
    """Check directory permissions"""
    cur_stat = os.stat(cur_path)
    cur_mode = stat.S_IMODE(cur_stat.st_mode)
    if cur_mode != 0o700:
        raise RuntimeError("The permission of ssl directory should be 700")


def _check_invalid_ssl_filesize(ssl_options: Dict[str, str]) -> None:
    """Check SSL file size"""
    def check_size(path: str):
        size = os.path.getsize(path)
        if size > max_size:
            raise RuntimeError(f"SSL file should not exceed 10MB!")

    max_size = 10 * 1024 * 1024  # Maximum file size is 10MB
    for ssl_key in SSL_MUST_KEYS:
        check_size(ssl_options[ssl_key])


def _check_invalid_ssl_path(ssl_options: Dict[str, str], required_keys: Optional[list] = None) -> None:
    """Check SSL path validity"""
    def check_single(key: str, path: str):
        if not os.path.exists(path):
            raise RuntimeError(f"Enum {key} path is invalid: {path}")
        _check_directory_permissions(os.path.dirname(path))

    if not isinstance(ssl_options, dict):
        raise RuntimeError("ssl_options should be a dict!")
    
    keys_to_check = required_keys if required_keys is not None else SSL_MUST_KEYS
    for ssl_key in keys_to_check:
        if ssl_key not in ssl_options.keys():
            raise RuntimeError(f"{ssl_key} should be provided when ssl enable!")
        check_single(ssl_key, ssl_options[ssl_key])


class CertUtil:
    """Certificate utility class"""
    
    @classmethod
    def validate_revoke_list(cls, crl_file_path: str) -> bool:
        """Validate CRL revocation list"""
        try:
            with open(crl_file_path, 'rb') as ca_crl_file:
                ca_crl = crypto.load_crl(crypto.FILETYPE_PEM, ca_crl_file.read())

            next_update_time = ca_crl.to_cryptography().next_update
            current_time = datetime.datetime.now(timezone.utc)
            if current_time >= next_update_time:
                logger.error("Current time is later than next update time of CRL")
                return False

            # Check if CRL list is empty
            revoked_certs = ca_crl.get_revoked()
            if not revoked_certs:
                logger.warning("CRL list is empty")
                # Empty CRL list is not necessarily an error, just a warning
            return True

        except Exception as e:
            logger.error(f"CRL validation failed: {str(e)}")
            return False

    @classmethod
    def validate_ca_certs(cls, ca_crt_path: str) -> bool:
        """Validate CA certificate integrity and security"""
        try:
            with open(ca_crt_path, "rb") as ca_crt_file:
                ca_cert = crypto.load_certificate(crypto.FILETYPE_PEM, ca_crt_file.read())

            # 1. Check if certificate version is X509v3
            if ca_cert.get_version() != 2:
                logger.error(f"The CA: {os.path.basename(ca_crt_path)} does not use X509v3")
                return False

            decode_format = 'utf-8'
            
            # 2. Check CA flag and key usage
            check_ca_flag = False
            check_digital_signature_flag = False
            check_key_cert_sign = False
            check_crl_sign = False
            num_extensions = ca_cert.get_extension_count()
            for index in range(num_extensions):
                ext = ca_cert.get_extension(index)
                ext_name = ext.get_short_name()
                if ext_name.decode(decode_format) == "basicConstraints":
                    ext_content = str(ext)
                    if "CA:TRUE" in ext_content.upper():
                        check_ca_flag = True
                if ext_name.decode(decode_format) == "keyUsage":
                    ext_content = str(ext)
                    if "Digital Signature" in ext_content:
                        check_digital_signature_flag = True
                    if "Certificate Sign" in ext_content:
                        check_key_cert_sign = True
                    if "CRL Sign" in ext_content:
                        check_crl_sign = True

            # Validate basic constraints (CA flag)
            if not check_ca_flag:
                logger.error(f"The CA file {os.path.basename(ca_crt_path)} CA flag is not found in basic constraints")
                return False

            # Validate key usage
            if not check_digital_signature_flag:
                logger.error(f"The CA file {os.path.basename(ca_crt_path)} Digital Signature is not found in key usage")
                return False

            if not check_key_cert_sign:
                logger.error(f"The CA file {os.path.basename(ca_crt_path)} Certificate Sign is not found in key usage")
                return False

            if not check_crl_sign:
                logger.error(f"The CA file {os.path.basename(ca_crt_path)} CRL Sign is not found in key usage")
                return False

            # Validate signature algorithm
            pkey_algorithm = ca_cert.get_signature_algorithm().decode(decode_format)
            if pkey_algorithm not in [RSA_SHA_256, RSA_SHA_512]:
                logger.warning(f"CA {os.path.basename(ca_crt_path)} uses insecure encryption algorithm")

            # Check RSA key length
            pkey = ca_cert.get_pubkey()
            key_algorithm_id = pkey.type()
            if key_algorithm_id == crypto.TYPE_RSA:
                rsa_key = pkey.to_cryptography_key()
                rsa_length = rsa_key.key_size
                if rsa_length < MIN_RSA_LENGTH:
                    logger.error(f"{os.path.basename(ca_crt_path)} insecure RSA key length, "
                               f"required no less than: {MIN_RSA_LENGTH}")
                    return False

            # Calculate fingerprint
            fingerprint = ca_cert.digest(pkey_algorithm).decode(decode_format)
            logger.info(f"CA path: {os.path.basename(ca_crt_path)} pKeyAlgorithm: {pkey_algorithm} "
                       f"Fingerprint: {fingerprint}")

            # Check if certificate has expired
            if has_expired(ca_cert):
                logger.error(f"CA path: {os.path.basename(ca_crt_path)} CA cert expired")
                return False
            
            return True
        except Exception as e:
            logger.error(f"CA certificate validation failed: {str(e)}")
            return False

    @classmethod
    def query_cert_info(cls, crt_path: str) -> dict:
        """Query certificate detailed information"""
        try:
            with open(crt_path, "rb") as file:
                cert_data = file.read()
            cert = crypto.load_certificate(crypto.FILETYPE_PEM, cert_data)
            not_before = cert.get_notBefore().decode('utf-8')
            not_after = cert.get_notAfter().decode('utf-8')
            issuer = cert.get_issuer()
            issuer_msg = f'{issuer.CN}, {issuer.O}, {issuer.OU}, {issuer.L}, {issuer.ST}, {issuer.C}'
            subject = cert.get_subject()
            subject_msg = f'{subject.CN}, {subject.O}, {subject.OU}, {subject.L}, {subject.ST}, {subject.C}'
            serial_number = cert.get_serial_number()
            version = cert.get_version()
            return {
                'Not Before': not_before,
                'Not After': not_after,
                'Issuer': issuer_msg,
                'Subject': subject_msg,
                'Serial Number': serial_number,
                'Version': version
            }
        except Exception as e:
            logger.error(f"Certificate info query failed: {str(e)}")
            return {}

    @classmethod
    def query_crl_info(cls, crl_file_path: str) -> list:
        """Query CRL detailed information"""
        try:
            with open(crl_file_path, "r") as file:
                crl_data = file.read()
            crl = crypto.load_crl(crypto.FILETYPE_PEM, crl_data)
            # Get revoked certificates
            revoked_certs = crl.get_revoked()
            data = []
            if revoked_certs:
                for cert in revoked_certs:
                    serial_number = cert.get_serial().decode('utf-8')
                    revoked_reason = cert.get_reason()
                    revocation_date = cert.get_rev_date().decode('utf-8')
                    item = {
                        'Serial Number': serial_number,
                        'Revoked Reason': revoked_reason,
                        'Revocation Date': revocation_date
                    }
                    data.append(item)
            else:
                logger.info("No revoked certificates found in the CRL")
            return data
        except Exception as e:
            logger.error(f"CRL info query failed: {str(e)}")
            return []

    @classmethod
    def validate_cert_and_key_flexible(cls, server_crt_path: str, server_key_path: str, plain_text: bytes = None) -> bool:
        """
        does not enforce private key encryption
        
        Args:
            server_crt_path: Server certificate file path
            server_key_path: Server private key file path
            plain_text: Private key password (bytes format)
            
        Returns:
            Validation result
        """
        server_key = None
        try:
            # Load X509 certificate
            with open(server_crt_path, 'rb') as f:
                cert_data = f.read()
                server_cert = crypto.load_certificate(crypto.FILETYPE_PEM, cert_data)
            
            with open(server_key_path, 'rb') as f:
                key_data = f.read()
                
                # Flexible loading of private key, supports both encrypted and unencrypted formats
                try:
                    if not plain_text:
                        # Try to load unencrypted private key
                        server_key = crypto.load_privatekey(crypto.FILETYPE_PEM, key_data)
                        logger.info("Loaded unencrypted private key")
                    else:
                        # Try to load encrypted private key
                        server_key = crypto.load_privatekey(crypto.FILETYPE_PEM, key_data, passphrase=plain_text)
                        logger.info("Loaded encrypted private key")
                except crypto.Error as e:
                    # If loading fails, try another method
                    try:
                        if plain_text:
                            # If password exists but first load failed, try loading without password
                            server_key = crypto.load_privatekey(crypto.FILETYPE_PEM, key_data)
                            logger.warning("Loaded private key without password (password may be unnecessary)")
                        else:
                            # If loading without password fails, try loading with password
                            server_key = crypto.load_privatekey(crypto.FILETYPE_PEM, key_data, passphrase="")
                            logger.warning("Loaded private key with empty password")
                    except crypto.Error:
                        logger.error(f"Failed to load private key: {e}")
                        return False

            # Validate private key file
            if server_key is None:
                logger.error("Failed to load private key")
                return False

            # Validate server certificate (using lenient validation)
            try:
                # Only perform basic certificate validation, do not enforce all security constraints
                if server_cert.get_version() != 2:
                    logger.warning("Certificate does not use X509v3")
                
                # Check if certificate has expired
                if has_expired(server_cert):
                    logger.error("Server cert expired")
                    return False
                    
            except Exception as e:
                logger.warning(f"Certificate validation warning: {e}")

            # Validate if certificate and private key match
            if not validate_certs_and_keys_modulus(server_cert, server_key):
                logger.error("Certificate and private key modulus mismatch")
                return False
            
            return True
        except Exception as e:
            logger.error(f"Certificate and key validation failed: {str(e)}")
            return False

    @classmethod
    def validate_cert_and_key(cls, server_crt_path: str, server_key_path: str, plain_text: bytes = None) -> bool:
        """Validate certificate and private key integrity and matching"""
        server_key = None
        try:
            # Load X509 certificate
            with open(server_crt_path, 'rb') as f:
                cert_data = f.read()
                server_cert = crypto.load_certificate(crypto.FILETYPE_PEM, cert_data)
            
            with open(server_key_path, 'rb') as f:
                key_data = f.read()
                
                # Try to load private key, supports both encrypted and unencrypted formats
                try:
                    if not plain_text:
                        # Try to load unencrypted private key
                        server_key = crypto.load_privatekey(crypto.FILETYPE_PEM, key_data)
                        logger.info("Loaded unencrypted private key")
                    else:
                        # Try to load encrypted private key
                        server_key = crypto.load_privatekey(crypto.FILETYPE_PEM, key_data, passphrase=plain_text)
                        logger.info("Loaded encrypted private key")
                except crypto.Error as e:
                    # If loading fails, try another method
                    try:
                        if plain_text:
                            # If password exists but first load failed, try loading without password
                            server_key = crypto.load_privatekey(crypto.FILETYPE_PEM, key_data)
                            logger.warning("Loaded private key without password (password may be unnecessary)")
                        else:
                            # If loading without password fails, try loading with password
                            server_key = crypto.load_privatekey(crypto.FILETYPE_PEM, key_data, passphrase="")
                            logger.warning("Loaded private key with empty password")
                    except crypto.Error:
                        logger.error(f"Failed to load private key: {e}")
                        return False

            # Validate private key file
            if server_key is None:
                logger.error("Failed to load private key")
                return False

            # Validate server certificate
            if not validate_server_certs(server_cert):
                logger.error("Server certificate validation failed")
                return False

            # Validate if certificate and private key match
            if not validate_certs_and_keys_modulus(server_cert, server_key):
                logger.error("Certificate and private key modulus mismatch")
                return False
            
            return True
        except Exception as e:
            logger.error(f"Certificate and key validation failed: {str(e)}")
            return False

    @classmethod
    def validate_ca_crl(cls, ca_path: str, crl_path: str) -> bool:
        """Validate CRL signature match with CA certificate"""
        try:
            with open(crl_path, 'rb') as crl_path_file:
                ca_crl = crypto.load_crl(crypto.FILETYPE_PEM, crl_path_file.read())
            with open(ca_path, "rb") as ca_crt_file:
                ca_cert = crypto.load_certificate(crypto.FILETYPE_PEM, ca_crt_file.read())

            ca_pub_key = ca_cert.get_pubkey().to_cryptography_key()
            crl_crypto = ca_crl.to_cryptography()
            valid_signature = crl_crypto.is_signature_valid(ca_pub_key)
            if valid_signature:
                return True
            else:
                logger.error(f'CRL {os.path.basename(crl_path)} is not valid for CA {os.path.basename(ca_path)}')
                return False
        except Exception as e:
            logger.error(f"CRL signature validation failed: {str(e)}")
            return False


class CoordinatorCertUtil:
    """Coordinator证书工具类"""
    
    @classmethod
    def construct_cert_context(cls, config: Dict[str, str]) -> Optional[object]:
        """
        Construct certificate context - strict certificate validation
        
        Args:
            config: Certificate configuration dictionary
            
        Returns:
            SSL context object
        """
        try:
            # Check SSL configuration - create local copy to avoid modifying global state
            required_keys = SSL_MUST_KEYS.copy()
            if TLS_CRL in config:
                required_keys.append(TLS_CRL)
            
            _check_invalid_ssl_path(config, required_keys)
            _check_invalid_ssl_filesize(config)
            
            # Get password
            password = config.get("tls_passwd", "").encode('utf-8')
            
            # Use complete CA certificate validation
            if not CertUtil.validate_ca_certs(config[CA_CERTS]):
                raise RuntimeError("CA certificate validation failed")
            
            # Validate CRL (if provided)
            if TLS_CRL in config:
                if not CertUtil.validate_ca_crl(config[CA_CERTS], config[TLS_CRL]):
                    raise RuntimeError("CRL validation failed")
            
            # Use complete certificate and private key validation
            if not CertUtil.validate_cert_and_key(config[TLS_CERT], config[TLS_KEY], password):
                raise RuntimeError("Certificate and key validation failed")
            
            # Create SSL context
            context = create_default_context(Purpose.SERVER_AUTH)
            context.load_verify_locations(cafile=config[CA_CERTS])
            context.load_cert_chain(
                certfile=config[TLS_CERT],
                keyfile=config[TLS_KEY],
                password=password.decode('utf-8')
            )
            
            # Dynamically add attributes, save certificate path information
            context.cert_file = config.get(TLS_CERT, "")
            context.key_file = config.get(TLS_KEY, "")
            context.ca_file = config.get(CA_CERTS, "")
            context.password = password.decode('utf-8')
            
            logger.info("SSL certificate context constructed successfully with full validation")
            return context
            
        except Exception as e:
            logger.error(f"Failed to construct certificate context: {e}")
            return None
    
    @classmethod
    def create_ssl_context(cls, cert_file: str, key_file: str, ca_file: str, password: str = "") -> Optional[object]:
        """
        Create SSL context - using flexible validation
        
        Args:
            cert_file: Certificate file path
            key_file: Private key file path
            ca_file: CA certificate file path
            password: Private key password
            
        Returns:
            SSL context object
        """
        try:
            # Check if file paths are empty or non-existent
            if not cert_file or not key_file or not ca_file:
                logger.error("Certificate files cannot be empty")
                return None
            
            if not os.path.exists(cert_file) or not os.path.exists(key_file) or not os.path.exists(ca_file):
                logger.error(f"Certificate files do not exist: cert={cert_file}, key={key_file}, ca={ca_file}")
                return None
            
            # Use flexible certificate validation
            if not CertUtil.validate_ca_certs(ca_file):
                logger.warning("CA certificate validation failed, but continuing with SSL context creation")
            
            password_bytes = password.encode('utf-8') if password else None
            if not CertUtil.validate_cert_and_key_flexible(cert_file, key_file, password_bytes):
                logger.warning("Certificate and key validation failed, but continuing with SSL context creation")
            
            # Create SSL context
            context = create_default_context(Purpose.SERVER_AUTH)
            
            # Load CA certificate
            context.load_verify_locations(cafile=ca_file)
            
            # Try to load certificate chain, support both encrypted and unencrypted private keys
            try:
                context.load_cert_chain(
                    certfile=cert_file,
                    keyfile=key_file,
                    password=password if password else None
                )
                logger.info("SSL context created successfully with certificate chain")
            except Exception as e:
                # If loading fails, try without password
                try:
                    context.load_cert_chain(
                        certfile=cert_file,
                        keyfile=key_file
                    )
                    logger.warning(f"SSL context created with certificate chain (without password): {e}")
                except Exception as e2:
                    logger.error(f"Failed to load certificate chain: {e2}")
                    return None
            
            logger.info("SSL context created successfully")
            return context
            
        except Exception as e:
            logger.error(f"Failed to create SSL context: {e}")
            return None
    
    @classmethod
    def create_ssl_context_no_client_cert(cls, cert_file: str, key_file: str, ca_file: str = "", password: str = "") -> Optional[object]:
        """
        Create SSL context without requiring client certificate verification
        
        Args:
            cert_file: Certificate file path
            key_file: Private key file path
            ca_file: CA certificate file path (optional, for client cert verification)
            password: Private key password
            
        Returns:
            SSL context object
        """
        try:
            # Check if file paths are empty or non-existent
            if not cert_file or not key_file:
                logger.error("Certificate files cannot be empty")
                return None
            
            if not os.path.exists(cert_file) or not os.path.exists(key_file):
                logger.error(f"Certificate files do not exist: cert={cert_file}, key={key_file}")
                return None
            
            # CA file is optional for this method (no client cert verification)
            if ca_file and not os.path.exists(ca_file):
                logger.warning(f"CA certificate file does not exist: {ca_file}, continuing without CA verification")
                ca_file = ""
            
            password_bytes = password.encode('utf-8') if password else None
            if not CertUtil.validate_cert_and_key_flexible(cert_file, key_file, password_bytes):
                logger.warning("Certificate and key validation failed, but continuing with SSL context creation")
            
            # Create SSL context (no client cert verification)
            context = create_default_context(Purpose.SERVER_AUTH)
            context.check_hostname = False
            context.verify_mode = ssl.CERT_NONE  # Don't require client certificates
            
            # Load CA certificate if provided (for server cert validation)
            if ca_file:
                try:
                    context.load_verify_locations(cafile=ca_file)
                except Exception as e:
                    logger.warning(f"Failed to load CA certificate: {e}, continuing without CA verification")
            
            # Try to load certificate chain, support both encrypted and unencrypted private keys
            try:
                context.load_cert_chain(
                    certfile=cert_file,
                    keyfile=key_file,
                    password=password if password else None
                )
                logger.info("SSL context created successfully with certificate chain (no client cert verification)")
            except Exception as e:
                # If loading fails, try without password
                try:
                    context.load_cert_chain(
                        certfile=cert_file,
                        keyfile=key_file
                    )
                    logger.warning(f"SSL context created with certificate chain (without password): {e}")
                except Exception as e2:
                    logger.error(f"Failed to load certificate chain: {e2}")
                    return None
            
            logger.info("SSL context created successfully (no client cert verification)")
            return context
            
        except Exception as e:
            logger.error(f"Failed to create SSL context (no client cert): {e}")
            return None
    
    @staticmethod
    def query_certificate_info(cert_file: str) -> dict:
        """
        Query certificate detailed information
        
        Args:
            cert_file: Certificate file path
            
        Returns:
            Certificate information dictionary
        """
        return CertUtil.query_cert_info(cert_file)
    
    @staticmethod
    def query_crl_info(crl_file: str) -> list:
        """
        Query CRL detailed information
        
        Args:
            crl_file: CRL file path
            
        Returns:
            CRL information list
        """
        return CertUtil.query_crl_info(crl_file)
    
    @staticmethod
    def validate_certificate_chain(ca_file: str, cert_file: str, key_file: str, crl_file: str = None, password: str = "") -> bool:
        """
        Validate complete certificate chain
        
        Args:
            ca_file: CA certificate file path
            cert_file: Certificate file path
            key_file: Private key file path
            crl_file: CRL file path (optional)
            password: Private key password
            
        Returns:
            Validation result
        """
        try:
            # Validate CA certificate
            if not CertUtil.validate_ca_certs(ca_file):
                logger.error("CA certificate validation failed")
                return False
            
            # Validate CRL (if provided)
            if crl_file and os.path.exists(crl_file):
                if not CertUtil.validate_ca_crl(ca_file, crl_file):
                    logger.error("CRL validation failed")
                    return False
            
            # Validate certificate and private key
            password_bytes = password.encode('utf-8') if password else None
            if not CertUtil.validate_cert_and_key(cert_file, key_file, password_bytes):
                logger.error("Certificate and key validation failed")
                return False
            
            logger.info("Certificate chain validation completed successfully")
            return True
            
        except Exception as e:
            logger.error(f"Certificate chain validation failed: {e}")
            return False
